package com.blog.web.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.blog.common.core.domain.R;
import com.blog.common.core.utils.HTMLUtils;
import com.blog.common.core.utils.PageUtils;
import com.blog.common.core.utils.ip.IpUtils;
import com.blog.common.core.web.page.TableDataInfo;
import com.blog.common.domain.dto.CommentDto;
import com.blog.common.domain.entity.Comment;
import com.blog.common.domain.entity.SiteConfig;
import com.blog.common.domain.vo.CommentVo;
import com.blog.common.domain.vo.ReplyCountVo;
import com.blog.common.domain.vo.ReplyVo;
import com.blog.common.redis.service.RedisService;
import com.blog.message.api.MQproduct.CommentProduct;
import com.blog.system.api.feign.RemoteConfigService;
import com.blog.common.mapper.dao.CommentMapper;
import com.blog.web.service.CommentService;
import com.blog.web.service.UserInfoService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import static com.blog.common.core.constant.ServiceConst.*;
import static com.blog.common.core.constant.CacheConstants.*;

/**
 * <p>
 * 评论 服务实现类
 * </p>
 *
 * @author Valerie
 * @since 2023-02-18
 */
@Service
public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> implements CommentService {

    @Resource
    private CommentMapper commentMapper;

    @Resource
    private RedisService redisService;

    @Resource
    private RemoteConfigService remoteConfigService;

    @Resource
    private HttpServletRequest request;

    @Resource
    private UserInfoService userInfoService;

    @Resource
    private CommentProduct commentProduct;



    @Override
    public TableDataInfo<CommentVo> listComments(CommentDto commentDto) {
        Long commentCount = commentMapper.selectCount(
                new LambdaQueryWrapper<Comment>()
                        .eq(ObjUtil.isNotNull(commentDto.getTopicId()), Comment::getTopicId, commentDto.getTopicId())
                        .eq(Comment::getType, commentDto.getType())
                        .isNull(Comment::getParentId)
                        .eq(Comment::getIsReview, IS_TRUE)
        );
        if (commentCount == 0){
            return new TableDataInfo<>();
        }
        // 分页查询评论数据
        Page<CommentVo> commentVoPage = commentMapper.listComments(PageUtils.getPage(), commentDto);
        List<CommentVo> commentVoList = commentVoPage.getRecords();
        if (CollectionUtil.isEmpty(commentVoList)){
            return new TableDataInfo<>();
        }
        Map<Object, Object> likeCountMap = redisService.hGetAll(COMMENT_LIKE_COUNT);
        List<Long> commentIdList = commentVoList.stream().map(CommentVo::getId).collect(Collectors.toList());
        List<ReplyVo> replyVoList = commentMapper.listReplies(commentIdList);
        //组装
        Map<Long, List<ReplyVo>> replyVoByIdMap = replyVoList.stream().collect(Collectors.groupingBy(ReplyVo::getReplyId));
        replyVoList = replyVoList.stream().peek(item -> {
            item.setReplyVoList(replyVoByIdMap.getOrDefault(item.getId(), null));
        }).collect(Collectors.toList());

        // 根据评论id分组回复数据
        Map<Long, List<ReplyVo>> replyMap = replyVoList.stream()
                .collect(Collectors.groupingBy(ReplyVo::getReplyId));
        replyVoList = replyVoList.stream().peek(e -> e.setLikeCount(Optional.ofNullable((Long) likeCountMap.get(e.getId())).orElse(0L))).collect(Collectors.toList());
        Map<Long, Long> replyCountMap = commentMapper.listReplyCountByCommentId(commentIdList).stream().collect(Collectors.toMap(ReplyCountVo::getCommentId, ReplyCountVo::getReplyCount));
        // 封装评论数据
        commentVoList = commentVoList.stream().peek(item -> {
            item.setLikeCount((Long) likeCountMap.get(item.getId().toString()));
            item.setReplyVoList(replyMap.get(item.getId()));
            item.setReplyCount(replyCountMap.get(item.getId()));
        }).collect(Collectors.toList());
        return new TableDataInfo<>(commentVoList, commentVoPage.getTotal());
    }



    @Override
    public void saveComment(CommentDto commentDto) {
        userInfoService.insertUserByComment(commentDto);
        R<SiteConfig> r = remoteConfigService.getWebsiteConfig();
        SiteConfig siteConfig = r.getData();
        Integer isCommentReview = siteConfig.getCommentCheck();
        commentDto.setCommentContent(HTMLUtils.deleteTag(commentDto.getCommentContent()));
        Comment comment = BeanUtil.copyProperties(commentDto, Comment.class);
        comment.setId(IdUtil.getSnowflakeNextId());
        boolean save = this.save(comment);
        if (save){
            commentProduct.review(comment);
        }
        if (siteConfig.getEmailNotice().equals(IS_TRUE)){
            // todo
        }
    }

    @Override
    public List<ReplyVo> listRepliesByCommentId(Serializable commentId) {
        Page<ReplyVo> replyVoPage = commentMapper.listRepliesByCommentId(PageUtils.getPage(), Long.parseLong(commentId.toString()));
        // 查询redis中的点赞map
        Map<Object, Object> countLikeMap = redisService.hGetAll(COMMENT_USER_LIKE);
        List<ReplyVo> replyVoList = replyVoPage.getRecords();
        Map<Long, List<ReplyVo>> replyByIdMap = replyVoList.stream().collect(Collectors.groupingBy(ReplyVo::getReplyId));
        replyVoList = replyVoList.stream()
                .peek(p -> p.setReplyVoList(replyByIdMap.getOrDefault(p.getId(), null)))
                .collect(Collectors.toList());

        // 封装点赞数
        return replyByIdMap.get(Long.parseLong(commentId.toString()));
    }

    @Override
    public void saveCommentLike(Serializable commentId) {
        // 唯一标识
        // Todo 暂时使用ip
        String commentUserLike = COMMENT_USER_LIKE + IpUtils.getIpAddr(request);
        // 判断set是否包含标识
        if (redisService.sIsMember(commentUserLike, commentId)){
            // 移除标识
            redisService.sRemove(COMMENT_USER_LIKE, commentId);
            // 点赞减一
            redisService.zDecrement(COMMENT_LIKE_COUNT, commentId, 1.0);
        }else {
            // 增加标识
            redisService.sAdd(commentUserLike, commentId);
            // 点赞加一
            redisService.zIncrement(COMMENT_LIKE_COUNT, commentId, 1.0);
        }

    }
}
